using System;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;
using HengTong.Model.Db.Hr.Attendance;
using WalkingTec.Mvvm.Core;
using Microsoft.Extensions.DependencyInjection;
using HengTong.Model.Services;
using TiaoTaoHelper.Models;
using UUIDNext;
using HengTong.Model.Db.Hr.Bill;
using HengTong.Model.Extension;
using Microsoft.EntityFrameworkCore;
using TiaoTaoHelper.Wtm.Models;
using TiaoTaoHelper.Wtm.Interfaces;


namespace HengTong.ViewModel.Daily.SysDailyShiftSwapRequestBillVms
{
    public partial class SysDailyShiftSwapRequestBillVm : CrudVm<SysDailyShiftSwapRequestBill>
    {
        public SysDailyShiftSwapRequestBillVm()
        {
            SetInclude(x => x.Person);
            SetInclude(x => x.SwapPerson);
            SetInclude(x => x.Group);
            SetInclude(x => x.Org);
        }

        protected override void InitVM()
        {
            base.InitVM();
        }

        public override async Task DoAddAsync()
        {
            // 校验必填字段
            if (!Entity.PersonId.HasValue)
            {
                MSD.AddModelError(" ", "员工不能为空");
                return;
            }

            if (!Entity.SwapPersonId.HasValue && !Entity.SwapShiftId.HasValue)
            {
                MSD.AddModelError(" ", "换班人员或换班记录ID不能为空");
                return;
            }

            if (!Entity.StartTime.HasValue)
            {
                MSD.AddModelError(" ", "换班日期不能为空");
                return;
            }

            // 获取系统配置中的替班月度限制
            var substitutionMonthlyLimit = Wtm.GetSiteConfig().SubstitutionMonthlyLimit;

            // 检查当月替班申请次数是否超过限制
            var currentMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
            var nextMonth = currentMonth.AddMonths(1);

            var monthlyCount = await DC.Set<SysDailyShiftSwapRequestBill>()
                .AsNoTracking()
                .Where(x => x.PersonId == Entity.PersonId.Value
                            && x.StartTime >= currentMonth
                            && x.StartTime < nextMonth
                            && x.WorkflowStatus != WorkflowStatus.已取消)
                .CountAsync();

            if (monthlyCount >= substitutionMonthlyLimit)
            {
                MSD.AddModelError(" ",
                    $"人员{Entity.Name}({Entity.StaffNo})本月替班申请次数已达到上限({substitutionMonthlyLimit}次)");
                return;
            }

            //暂定一天，结束时间等于开始时间
            Entity.EndTime = Entity.StartTime;

            using var transactionScope = new TransactionScope(
                TransactionScopeOption.Required,
                new TransactionOptions
                {
                    IsolationLevel = IsolationLevel.ReadCommitted,
                    Timeout = TimeSpan.FromMinutes(10)
                },
                TransactionScopeAsyncFlowOption.Enabled);

            try
            {
                // 检查换班日期是否在允许范围内（前后60天）
                var shiftDate = Entity.StartTime.Value;
                var currentDate = DateTime.Now;
                var minDate = currentDate.AddDays(-60);
                var maxDate = currentDate.AddDays(60);

                if (shiftDate < minDate || shiftDate > maxDate)
                {
                    MSD.AddModelError(" ", "换班日期不能超过当前日期前后60天范围");
                    return;
                }

                // 转换为DateOnly进行查询
                var shiftDateOnly = DateOnly.FromDateTime(shiftDate);

                // 查询换班日期的考勤记录
                var existingRecord = await DC.Set<SysAttendanceRecord>()
                    .AsNoTracking()
                    .Where(x => x.PersonId == Entity.PersonId.Value
                                && x.ShiftDate == shiftDateOnly
                                && x.Status == ShiftStatusEnum.正常)
                    .FirstOrDefaultAsync();

                // 检查是否存在排班记录
                if (existingRecord == null)
                {
                    var person = await DC.Set<Model.Db.Hr.SysPerson>()
                        .Where(x => x.ID == Entity.PersonId.Value)
                        .Select(x => x.Name)
                        .FirstOrDefaultAsync();

                    MSD.AddModelError(" ",
                        $"人员{person ?? Entity.PersonId.Value.ToString()}在{shiftDateOnly}没有排班记录, 只能对已有排班记录进行换班操作");
                    return;
                }

                // 检查是否已有考勤结果
                if (existingRecord.AttendanceResult != AttendanceResultEnum.未计算)
                {
                    var person = await DC.Set<Model.Db.Hr.SysPerson>()
                        .Where(x => x.ID == Entity.PersonId.Value)
                        .Select(x => x.Name)
                        .FirstOrDefaultAsync();

                    MSD.AddModelError(" ",
                        $"人员{person ?? Entity.PersonId.Value.ToString()}在{shiftDateOnly}的排班已经有考勤结果，无法申请换班");
                    return;
                }

                // 检查换班记录是否存在
                var swapRecord = await DC.Set<SysAttendanceRecord>()
                    .AsNoTracking()
                    .Where(x => x.ID == Entity.SwapShiftId)
                    .FirstOrDefaultAsync();

                if (swapRecord == null)
                {
                    MSD.AddModelError(" ", "换班关联记录不存在");
                    return;
                }

                // 检查换班人是否为自己
                if (swapRecord.PersonId == Entity.PersonId)
                {
                    MSD.AddModelError(" ", "换班关联不能是同一个人");
                    return;
                }

                // 检查换班记录是否已有考勤结果
                if (swapRecord.AttendanceResult != AttendanceResultEnum.未计算)
                {
                    var swapPerson = await DC.Set<Model.Db.Hr.SysPerson>()
                        .Where(x => x.ID == swapRecord.PersonId)
                        .Select(x => x.Name)
                        .FirstOrDefaultAsync();

                    MSD.AddModelError(" ",
                        $"换班人员{swapPerson ?? swapRecord.PersonId.ToString()}在{swapRecord.ShiftDate}的排班已经有考勤结果, 无法换班");
                    return;
                }

                // 检查换班记录的类型是否为正常上班
                if (swapRecord.ShiftType != ShiftTypeEnum.正常上班)
                {
                    var swapPerson = await DC.Set<Model.Db.Hr.SysPerson>()
                        .Where(x => x.ID == swapRecord.PersonId)
                        .Select(x => x.Name)
                        .FirstOrDefaultAsync();

                    MSD.AddModelError(" ",
                        $"换班人员{swapPerson ?? swapRecord.PersonId.ToString()}在{swapRecord.ShiftDate}的排班为:{swapRecord.ShiftType}, 无法换班");
                    return;
                }

                // 设置换班人员ID（如果未设置）
                if (!Entity.SwapPersonId.HasValue && swapRecord != null)
                {
                    Entity.SwapPersonId = swapRecord.PersonId;

                    // 可选：填充其他换班人员信息
                    var swapPerson = await DC.Set<Model.Db.Hr.SysPerson>()
                        .Where(x => x.ID == swapRecord.PersonId)
                        .FirstOrDefaultAsync();

                    if (swapPerson != null)
                    {
                        Entity.SwapStaffNo = swapPerson.StaffNo;
                        Entity.SwapName = swapPerson.Name;
                    }
                }

                // 单据处理逻辑
                if (Entity is IBill bill)
                {
                    Entity.BillStatus = BillStatus.草稿;
                    Entity.WorkflowStatus = WorkflowStatus.待提交;
                    var result = await GenerateCodeAsync();
                    if (result.Code == 200)
                    {
                        Entity.BillCode = result.Data;
                    }
                    else
                    {
                        MSD.AddModelError(" ", $"生成编码异常. {result.Message}");
                        return;
                    }
                }

                Entity.ID = Uuid.NewDatabaseFriendly(Database.SqlServer);
                if (Entity is IBasePoco poco)
                {
                    poco.CreateBy = Entity.StaffNo;
                    poco.UpdateBy = Wtm.LoginUserInfo?.ITCode;
                    poco.CreateTime = DateTime.Now;
                    poco.UpdateTime = DateTime.Now;
                }

                await base.DoAddAsync();

                // 如果所有操作成功，提交事务
                if (MSD.IsValid)
                {
                    transactionScope.Complete();
                }
            }
            catch (Exception e)
            {
                // TransactionScope会自动回滚，无需手动操作
                MSD.AddModelError(" ", $"换班申请操作异常: {e.Message}");
            }
        }


        public override async Task DoEditAsync(bool updateAllFields = false)
        {
            //暂定一天，结束时间等于开始时间
            Entity.EndTime = Entity.StartTime;
            if (Entity is IBill { WorkflowStatus: WorkflowStatus.提交中 })
            {
                var raw = await DC.Set<SysDailyShiftSwapRequestBill>()
                    .AsNoTracking()
                    .FirstOrDefaultAsync(e => e.ID == Entity.ID);
                if (raw.WorkflowStatus != WorkflowStatus.待提交)
                {
                    MSD.AddModelError(" ", "单据已提交审核,请勿重复提交.");
                    return;
                }

                var result = await StartWorkflowAsync("换班申请流程");
                if (result == null) return;
                if (!result.Executed)
                {
                    MSD.AddModelError(" ", $"提交审核异常. {result.Exception?.Message}");
                    return;
                }

                Entity.BillStatus = BillStatus.正文;
                Entity.WorkflowStatus = WorkflowStatus.审核中;
            }

            if (Entity is IBasePoco poco)
            {
                poco.UpdateBy = Wtm.LoginUserInfo?.ITCode;
                poco.UpdateTime = DateTime.Now;
            }

            await base.DoEditAsync(updateAllFields);
        }

        /// <summary>
        /// 必须使用异步事务, 否则工作流引擎会和当前事务冲突
        /// </summary>
        /// <param name="upAllFields"></param>
        public async Task ApproveAsync(bool upAllFields = false)
        {
            using var transactionScope = new TransactionScope(
                TransactionScopeOption.Required,
                new TransactionOptions
                {
                    IsolationLevel = IsolationLevel.ReadCommitted,
                    Timeout = TimeSpan.FromMinutes(10) // 增加超时时间到10分钟
                },
                TransactionScopeAsyncFlowOption.Enabled);
            try
            {
                if (Entity.BillStatus == BillStatus.草稿) Entity.BillStatus = BillStatus.正文;
                Entity.Approver = Wtm.LoginUserInfo?.ITCode;
                Entity.ApprovalTime = DateTime.Now;
                await base.DoEditAsync(upAllFields);
                if (MSD.IsValid)
                    if (MSD.IsValid)
                    {
                        var result = await ContinueWorkflowAsync(ActionName, Remark, "换班申请流程");
                        if (result.Executed == true)
                        {
                            transactionScope.Complete(); // 提交事务
                        }
                        else
                        {
                            MSD.AddModelError(" ", $"工作流执行失败");
                        }
                    }
                // 如果到这里，事务会自动回滚
            }
            catch (Exception e)
            {
                // TransactionScope会自动回滚，无需手动操作
                MSD.AddModelError(" ", $"审批操作异常: {e.Message}");
            }
        }

        /// <summary>
        /// 生成编码
        /// </summary>
        /// <returns></returns>
        public async Task<Result<string>> GenerateCodeAsync()
        {
            if (Entity is IBill bill)
            {
                var scope = Wtm.ServiceProvider.CreateScope();
                var service = scope.ServiceProvider.GetRequiredService<CodeGeneratorService>();
                var code = await service.GenerateCodeAsync(Entity.GetType().Name);
                return new Result<string>()
                {
                    Data = code
                };
            }

            return new Result<string>("实体未实现IBill接口");
        }

        /// <summary>
        /// 预测编码
        /// </summary>
        /// <returns></returns>
        public async Task<Result<string>> PredictCodeAsync()
        {
            if (Entity is IBill bill)
            {
                var scope = Wtm.ServiceProvider.CreateScope();
                var service = scope.ServiceProvider.GetRequiredService<CodeGeneratorService>();
                var code = await service.PreviewNextCodeAsync(Entity.GetType().Name);
                return new Result<string>()
                {
                    Data = code
                };
            }

            return new Result<string>("实体未实现IBill接口");
        }
    }
}